package sunline2ngbc.base_enum_dict;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.agile4j.plugin.gun.utils.FreeMarkerUtil;
import org.agile4j.plugin.gun.utils.ParserUtil;
import org.agile4j.plugin.gun.xml.dict.ComplexType;
import org.agle4j.framework.utils.CollectionUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.junit.Test;

/**
 * 根据sunline的 base;enum;dict生成 
 * ngbc模式的 base;enum;dict
 * 
 * @author Administrator
 */
public class GunClient {
	private static final Logger LOGGER = LogManager.getLogger(GunClient.class);

	private static final String PATH = "E:\\sunline_xml\\" ;
	
	private static org.agile4j.plugin.gun.xml.basetype.Schema baseEntity ;
	private static org.agile4j.plugin.gun.xml.baseenumtype.Schema enumEntity ;
	private static org.agile4j.plugin.gun.xml.dict.Schema ltDictEntity ;
	private static org.agile4j.plugin.gun.xml.dict.Schema dpDictEntity ;
	private static List<org.agile4j.plugin.gun.xml.dict.Schema> dictEntityList = new ArrayList<>();
	private static Map<String, Integer> newdictIdMap = new HashMap<>();
	
	private static Map<String, Document> docMap = new HashMap<>();
	private static final String BAEE_TYPE_DOC = "baseType.xml" ;
	private static final String BAEE_ENUM_TYPE_DOC = "sysEnumType.xml" ;
	private static final String BASE_DICT_TYPE_DOC ="dataDictionary.xml";
	
	/**
	 * 解析sunline的xml并生成java bean
	 * 1)加载全部xml
	 * 2)根据dict筛选enum以及base
	 */
	@Test
	public void setp1() {
		//1)加载全部xml
		String basePath = PATH + "BaseType.u_schema.xml" ;
		String enumPath = PATH + "BaseEnumType.e_schema.xml" ;
		String ltDictPath = PATH + "LtDict.d_schema.xml" ;
		String dpDictPath = PATH + "DpDict.d_schema.xml" ;
		getBaseSchema(basePath);
		getEnumSchema(enumPath);
		getDictSchema(ltDictPath);
		getDpDictSchema(dpDictPath);
		dictEntityList.add(ltDictEntity);
		dictEntityList.add(dpDictEntity);
		//2)根据dict筛选enum以及base
		//2.1 dict => set
		Set<String> set = new HashSet<>() ;
		Map<String, Integer> dictIdMap = new HashMap<>();
		for (org.agile4j.plugin.gun.xml.dict.Schema schema : dictEntityList) {
			for (Object obj : schema.getDescriptionOrComplexType()) {
				if (obj instanceof ComplexType) {
					ComplexType complexType = (ComplexType) obj;
					for (Object obj1 : complexType.getElementOrDescription()) {
						if (obj1 instanceof org.agile4j.plugin.gun.xml.dict.Element) {
							org.agile4j.plugin.gun.xml.dict.Element element = (org.agile4j.plugin.gun.xml.dict.Element) obj1;
							set.add(element.getType()) ;
							if (dictIdMap.containsKey(element.getId())) {
								dictIdMap.put(element.getId(),dictIdMap.get(element.getId()) + 1) ;
							} else {
								dictIdMap.put(element.getId(),1) ;
							}
						}
					}
				}
			}
		}
		LOGGER.debug(dictIdMap.size());
		for (Map.Entry<String, Integer> dictIdEntry : dictIdMap.entrySet()) {
			if (dictIdEntry.getValue() > 1) {
				newdictIdMap.put(dictIdEntry.getKey(),dictIdEntry.getValue());
			}
		}
		LOGGER.debug(newdictIdMap.size());
		//2.2 base remove set中不存在的节点
//		Iterator<org.agile4j.plugin.gun.xml.basetype.RestrictionType> ite = baseEntity.getRestrictionType().iterator() ;
//		LOGGER.debug("baseEntity01 : " + baseEntity.getRestrictionType().size());
//		while (ite.hasNext()) {
//			org.agile4j.plugin.gun.xml.basetype.RestrictionType vo = ite.next() ;
//			vo.setId(StringUtils.replace(vo.getId(), "U_", "B_"));
//			if (!set.contains(id)) {
//				ite.remove();
//			}
//		}
//		LOGGER.debug("baseEntity02 : " + baseEntity.getRestrictionType().size());
		//2.3 enum remove set中不存在的节点
		Iterator<org.agile4j.plugin.gun.xml.baseenumtype.RestrictionType> iteEnum = enumEntity.getRestrictionType().iterator() ;
		LOGGER.debug("enumEntity01 : " + enumEntity.getRestrictionType().size());
		while (iteEnum.hasNext()) {
			org.agile4j.plugin.gun.xml.baseenumtype.RestrictionType vo = iteEnum.next() ;
//			vo.setId(StringUtils.replace(vo.getId(), "E_", "L_"));
			String id = "BaseEnumType." + vo.getId() ;
			if (!set.contains(id)) {
				iteEnum.remove();
			}
		}
		LOGGER.debug("enumEntity02 : " + enumEntity.getRestrictionType().size());
		LOGGER.debug("setp1 : 解析sunline的xml并生成java bean");
	}
	
	private void getBaseSchema(String path){
		Map<String, org.agile4j.plugin.gun.xml.basetype.Schema> schemaMap = ParserUtil.deplogyBaseType(new File(path));
		if (CollectionUtil.isNotEmpty(schemaMap)) {
			for (Map.Entry<String, org.agile4j.plugin.gun.xml.basetype.Schema> schemaEntry : schemaMap.entrySet()) {
				baseEntity = schemaEntry.getValue();
			}
		}
	}
	private void getEnumSchema(String path){
		Map<String, org.agile4j.plugin.gun.xml.baseenumtype.Schema> schemaMap = ParserUtil.deplogyBaseEnumBaseType(new File(path));
		if (CollectionUtil.isNotEmpty(schemaMap)) {
			for (Map.Entry<String, org.agile4j.plugin.gun.xml.baseenumtype.Schema> schemaEntry : schemaMap.entrySet()) {
				enumEntity = schemaEntry.getValue();
			}
		}
	}
	private void getDictSchema(String path){
		Map<String, org.agile4j.plugin.gun.xml.dict.Schema> schemaMap = ParserUtil.deplogyDict(new File(path));
		if (CollectionUtil.isNotEmpty(schemaMap)) {
			for (Map.Entry<String, org.agile4j.plugin.gun.xml.dict.Schema> schemaEntry : schemaMap.entrySet()) {
				ltDictEntity = schemaEntry.getValue();
			}
		}
	}
	private void getDpDictSchema(String path){
		Map<String, org.agile4j.plugin.gun.xml.dict.Schema> schemaMap = ParserUtil.deplogyDict(new File(path));
		if (CollectionUtil.isNotEmpty(schemaMap)) {
			for (Map.Entry<String, org.agile4j.plugin.gun.xml.dict.Schema> schemaEntry : schemaMap.entrySet()) {
				dpDictEntity = schemaEntry.getValue();
			}
		}
	}
	
	/**
	 * 初始化ngbc的 document
	 */
	@Test
	public void setp2() throws DocumentException {
		File file1 = new File(PATH + "ngbc");
		Collection<File> collection = FileUtils.listFiles(file1, new String[] { "xml" }, true);
		for (File file : collection) {
			if (StringUtils.contains(file.getName(), BAEE_TYPE_DOC)) {
				docMap.put(BAEE_TYPE_DOC, loadDoc(file)) ;
			}
			if (StringUtils.equals(file.getName(), BAEE_ENUM_TYPE_DOC)) {
				docMap.put(BAEE_ENUM_TYPE_DOC, loadDoc(file)) ;
			}
			if (StringUtils.contains(file.getName(), BASE_DICT_TYPE_DOC)) {
				docMap.put(BASE_DICT_TYPE_DOC, loadDoc(file)) ;
			}
		}
	}
	
	private Document loadDoc(File file) throws DocumentException {
		SAXReader saxReader = new SAXReader();		
		Document doc = saxReader.read(file);		
		return doc;
	}
	
	private Document loadDoc(InputStream is) throws DocumentException {
		SAXReader saxReader = new SAXReader();		
		Document doc = saxReader.read(is);		
		return doc;
	}
	
	/**
	 * sunline java bean => ngbc xml
	 */
	@Test
	public void setp3() throws Exception {
		//1.生成 base
		Document baseDoc = docMap.get(BAEE_TYPE_DOC) ;
		Element baseRoot = (Element) baseDoc.getRootElement();
		for (org.agile4j.plugin.gun.xml.basetype.RestrictionType restrictionType : baseEntity.getRestrictionType()) {
			Element subEle = baseRoot.addElement("baseType") ;
			String type = restrictionType.getId() ;
			type = StringUtils.replace(type, "U_", "B_") ;
			subEle.addAttribute("id", type) ;
			subEle.addAttribute("desc", restrictionType.getLongname()) ;
			subEle.addAttribute("type", restrictionType.getBase()) ;
			if (restrictionType.getMaxLength() != null) {
				subEle.addAttribute("maxLength", String.valueOf(restrictionType.getMaxLength())) ;
			}
			if (restrictionType.getMinLength() != null) {
				subEle.addAttribute("minLength", String.valueOf(restrictionType.getMinLength())) ;
			}
			if (restrictionType.getFractionDigits() != null) {
				subEle.addAttribute("minLength", String.valueOf(restrictionType.getFractionDigits())) ;
			}
		}
		doc2XmlFile(baseDoc, baseDoc.getName().substring(getSubCount()));
		
		//2.生成 enum
		Document enumDoc = docMap.get(BAEE_ENUM_TYPE_DOC) ;
		Element enumRoot = (Element) enumDoc.getRootElement();
		Map<String, Object> enumMap = new HashMap<>();
		for (org.agile4j.plugin.gun.xml.baseenumtype.RestrictionType restrictionType : enumEntity.getRestrictionType()) {
			String type = restrictionType.getId() ;
			type = StringUtils.replace(type, "E_", "L_") ;
			enumMap.put("id", type) ;
			enumMap.put("desc", restrictionType.getLongname()) ;
			String base = StringUtils.replace(restrictionType.getBase(), "BaseType.", "") ;
			enumMap.put("baseTypeId", base) ;
			if (restrictionType.getEnumeration() != null) {
				if (CollectionUtil.isNotEmpty(restrictionType.getEnumeration())) {
					List<Map<String, Object>> mapList = new ArrayList<>();
					for (org.agile4j.plugin.gun.xml.baseenumtype.Enumeration enumeration : restrictionType.getEnumeration()) {
						Map<String, Object> enumSubMap = new HashMap<>();
						enumSubMap.put("id", enumeration.getId()) ;
						enumSubMap.put("value", enumeration.getValue()) ;
						enumSubMap.put("desc", enumeration.getLongname()) ;
						mapList.add(enumSubMap);
					}
					enumMap.put("enumSubList", mapList) ;
				}
			}
			String buildContent = FreeMarkerUtil.buildContent("enum.ftp", enumMap);
			try (InputStream is = new ByteArrayInputStream(buildContent.getBytes("UTF-8"))) {
				Document freeMarkdoc = loadDoc(is);
				enumRoot.add(freeMarkdoc.getRootElement());
			}
		}
		doc2XmlFile(enumDoc, enumDoc.getName().substring(getSubCount()));
		//3.生成 dict
		//3.1  生成基础数据类型集合
		Map<String, Map<String,Object>> map = new HashMap<>() ;
		for (org.agile4j.plugin.gun.xml.basetype.RestrictionType restrictionType : baseEntity.getRestrictionType()) {
			Map<String,Object> subMap = new HashMap<>() ;
			subMap.put("baseTypeId", restrictionType.getId());
			subMap.put("type", restrictionType.getBase());
			if (restrictionType.getMaxLength() != null) {
				subMap.put("maxLength", restrictionType.getMaxLength());
			}
			if (restrictionType.getMinLength() != null) {
				subMap.put("minLength", restrictionType.getMinLength());
			}
			if (restrictionType.getFractionDigits() != null) {
				subMap.put("scale", restrictionType.getFractionDigits());
			}
			map.put("BaseType." + restrictionType.getId(), subMap) ;
		}
		//3.1  生成枚举数据类型集合
		for (org.agile4j.plugin.gun.xml.baseenumtype.RestrictionType restrictionType : enumEntity.getRestrictionType()) {
			Map<String,Object> subMap = new HashMap<>() ;
			String type = restrictionType.getId();
			type = StringUtils.replace(type, "E_", "L_") ;
			subMap.put("enumTypeId", type) ;
			subMap.put("baseTypeId", restrictionType.getBase()) ;
			map.put("BaseEnumType." + restrictionType.getId(), subMap) ;
		}
		
		//3.2 解析并生成数据字典
		Document dictDoc = docMap.get(BASE_DICT_TYPE_DOC) ;
		Element dictRoot = (Element) dictDoc.getRootElement();
		
		for (org.agile4j.plugin.gun.xml.dict.Schema schema : dictEntityList) {
			for (Object obj : schema.getDescriptionOrComplexType()) {
				if (obj instanceof ComplexType) {
					ComplexType complexType = (ComplexType) obj;
					LOGGER.debug(complexType.getElementOrDescription().size());
					for (Object obj1 : complexType.getElementOrDescription()) {
						if (obj1 instanceof org.agile4j.plugin.gun.xml.dict.Element) {
							org.agile4j.plugin.gun.xml.dict.Element element = (org.agile4j.plugin.gun.xml.dict.Element) obj1;
							String baseData = element.getType() ;
							String dataType = baseData.startsWith("BaseType")?"1":"0" ;
							String baseTypeId = "" ;
							Element subDictRoot = dictRoot.addElement("element") ;
							subDictRoot.addAttribute("id", element.getId()) ;
							subDictRoot.addAttribute("desc", element.getLongname()) ;
							subDictRoot.addAttribute("dataType", dataType) ;
							Map<String, Object> searchMap = new HashMap<>();
							if ("0".equals(dataType)) {
								if (map.get(baseData) == null || map.get(baseData).get("enumTypeId") == null) {
									break ;
								}
								String enumTypeId = String.valueOf(map.get(baseData).get("enumTypeId")) ;
								subDictRoot.addAttribute("enumTypeId", enumTypeId) ;
								baseTypeId = String.valueOf(map.get(baseData).get("baseTypeId")) ;
								subDictRoot.addAttribute("baseTypeId", baseTypeId) ;
								searchMap = map.get(baseTypeId) ;
							} else {
								subDictRoot.addAttribute("baseTypeId", baseData) ;
								searchMap = map.get(baseData) ;
							}
							
							subDictRoot.addAttribute("type", String.valueOf(searchMap.get("type")));
							if (searchMap.get("maxLength") != null) {
								subDictRoot.addAttribute("maxLength", String.valueOf(searchMap.get("maxLength"))) ;
							}
							if (searchMap.get("minLength") != null) {
								subDictRoot.addAttribute("minLength", String.valueOf(searchMap.get("minLength"))) ;
							}
							if (searchMap.get("scale") != null) {
								subDictRoot.addAttribute("scale", String.valueOf(searchMap.get("scale"))) ;
							}
						}
					}
				}
			}
		}
		
		// 去重复
		List<Element> eleList = dictRoot.elements("element") ;
		LOGGER.debug("start:"+eleList.size());
		for (Element element : eleList) {
			String eleId = element.attributeValue("id") ;
			if (newdictIdMap.containsKey(eleId) && newdictIdMap.get(eleId) > 1) {
				newdictIdMap.put(eleId, newdictIdMap.get(eleId) - 1) ;
				dictRoot.remove(element) ;
			}
		}
		LOGGER.debug("end:"+dictRoot.elements("element").size());
		
		doc2XmlFile(dictDoc, dictDoc.getName().substring(getSubCount()));
	}
	
	private boolean doc2XmlFile(Document document, String filename) {
		boolean flag = true;
		XMLWriter writer = null;
		try {
			OutputFormat format = OutputFormat.createPrettyPrint();
			format.setEncoding("UTF-8");
			writer = new XMLWriter(new OutputStreamWriter(new FileOutputStream(filename)), format);
			writer.write(document);
			writer.close();
		} catch (Exception ex) {
			flag = false;
			ex.printStackTrace();
		}finally{
			if (null != writer){
				try {
					writer.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		LOGGER.debug(filename+"生成结果"+flag);
		return flag;
	}
	
	private static int getSubCount() {
		String osName = System.getProperty("os.name");
		return StringUtils.equalsIgnoreCase("Linux", osName)?6:7;
	}
}
